<?php


namespace app\xiangji\services;



use app\xiangji\exception\BadRequestException;
use app\xiangji\exception\GatewayException;
use app\xiangji\exception\ServiceUnavailableException;
use app\xiangji\jobs\WxPayOrderQueryJob;
use Carbon\Carbon;
use EasyWeChat\Factory;
use think\facade\Queue;

class PayService
{
    public $payment;

    public function wechat()
    {
        // 微信支付实例
        $this->payment = Factory::payment(config('wechat.payment'));
        return $this;
    }

    public function miniprogram(array $option = [], &$order_data = [])
    {
        $order_data = $this->unifiedOrder($option);
        // 处理返回
        $data = [
            'timeStamp' => (string)time(),
            'nonceStr'  => uniqid(),
            'package'   => 'prepay_id=' . $order_data['prepay_id'],
            'signType'  => 'MD5'
        ];
        // MD5加密
        $data['paySign'] = md5(
            sprintf(
                "appId=%s&nonceStr=%s&package=prepay_id=%s&signType=MD5&timeStamp=%s&key=%s",
                config('wechat.payment.app_id'),
                $data['nonceStr'],
                $order_data['prepay_id'],
                $data['timeStamp'],
                config('wechat.payment.key')
            )
        );
        return $data;
    }

    /**
     * @todo 微信统一下单接口
     * @param array $option
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws BadRequestException
     * @throws GatewayException
     * @throws ServiceUnavailableException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function unifiedOrder(array $option = [])
    {
        $default_option = [
            // 必传参数
            'openid'            => '',  // 用户标识
            'body'              => '',  // 商品描述
            'out_trade_no'      => '',  //
            'total_fee'         => '',
            'spbill_create_ip'  => request()->ip(),
            'trade_type'        => 'JSAPI',
            'notify_url'        => env('app.url') . '/weapp/wxpay/notify',
            // 非必传参数
            'detail'            => '',
            'attach'            => '',
            'fee_type'          => 'CNY',
            'time_start'        => Carbon::now()->format('YmdHis'),
            'time_expire'       => Carbon::now()->addHours(2)->format('YmdHis'),
            'scene_info'        => ''
        ];
        if (
            !$option['openid'] ||
            !$option['body'] ||
            !$option['out_trade_no'] ||
            !$option['total_fee'] || !is_numeric($option['total_fee'])
        ) {
            throw new BadRequestException('统一下单必要参数有误，请检查');
        }
        // 合并配置
        $option = array_merge($default_option, $option);
        try {
            $result = $this->payment->order->unify($option);
        }catch (\Exception $exception){
            throw new ServiceUnavailableException($exception->getMessage());
        }
        // 微信支付接口通信失败
        if ($result['return_code'] != 'SUCCESS'){
            throw new GatewayException('微信支付方通信失败，请稍后再试');
        }
        // 微信统一下单交易失败
        if ($result['result_code'] != 'SUCCESS'){
            // 记录下单失败err_code和err_code_des
        }
        // 开始轮询查询订单支付状态
        $this->wxpayStatusPolling($option['out_trade_no']);
        // 返回结果
        return $result;
    }

    /**
     * 定时轮询微信订单信息
     * @param string $out_trade_no
     */
    private function wxpayStatusPolling(string $out_trade_no):void
    {
        if (!$out_trade_no) return;
        // 每隔5秒/30秒/1分钟/3分钟/5分钟/10分钟/30分钟/1小时/2小时查询用户支付状态
        $delay_times = [5, 30, 60, 3 * 60, 5 * 60, 10 * 60, 30 * 60, 60 * 60, 2 * 60 * 60];
        foreach ($delay_times as $delay){
            Queue::later($delay, WxPayOrderQueryJob::class, $out_trade_no, 'query_pay_status');
        }
    }


    /**
     * @todo 查询微信支付订单状态
     * @param string $out_trade_no  自定义订单号
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     *
    [
    "return_code" => "SUCCESS"
    "return_msg" => "OK"
    "appid" => "wxbbcf11c4550b998c"
    "mch_id" => "1602404993"
    "nonce_str" => "IuceLxNK1UoRyKUm"
    "sign" => "C2BD6CBF091F3C89319DE2C85C81BB43"
    "result_code" => "SUCCESS"
    "openid" => "oDKSm5BWojmO1wpYEV1FzEGlWVuo"
    "is_subscribe" => "N"
    "trade_type" => "JSAPI"
    "bank_type" => "OTHERS"
    "total_fee" => "1"
    "fee_type" => "CNY"
    "transaction_id" => "4200000746202010138953856635"
    "out_trade_no" => "CZ202010130942319972313813"
    "attach" => null
    "time_end" => "20201013094225"
    "trade_state" => "SUCCESS"
    "cash_fee" => "1"
    "trade_state_desc" => "支付成功"
    "cash_fee_type" => "CNY"
    ]
     */
    public function queryWxPayByOutTradeNumber(string $out_trade_no)
    {
        return $this->payment->order->queryByOutTradeNumber($out_trade_no);
    }

    /**
     * @todo 关闭微信支付订单，已支付或超时的订单应关闭
     * @param string $out_trade_no  自定义订单号
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function closeWxPayOrder(string $out_trade_no)
    {
        return $this->payment->order->close($out_trade_no);
    }
}
